#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <thread>
#include <unordered_map>
#include <functional>

#include "json.hpp"
#include "user.hpp"
#include "group.hpp"
#include "public.hpp"

using namespace std;
using json = nlohmann::json;

// 记录当前登录的用户信息
User currentUser;

// 记录用户的好友列表信息
vector<User> currentUserFriendList;

// 记录当前用户的群组列表信息
vector<Group> currentUserGroupList;

// 系统支持的客户端命令列表
unordered_map<string, string> commandMap = {
    {"help", "显示所有支持的命令"},
    {"chat", "一对一聊天"},
    {"addfriend", "添加好友"},
    {"creategroup", "创建群组"},
    {"addgroup", "加入群组"},
    {"groupchat", "群聊"},
    {"loginout", "注销"},
    {"show","显示用户信息"}};

// 显示当前登录用户的基本信息
void showCurrentUserData(int)
{
    cout << "+------------------------------+" << endl;
    cout << "您的ID : " << currentUser.getId() << " 您的姓名 : " << currentUser.getName() << endl;
    cout << "+------------------------------+" << endl;
    cout << "您的好友 : " << endl;
    for (auto &user : currentUserFriendList)
    {
        cout << "您好友的ID : " << user.getId() << " 您好友的姓名 : " << user.getName() << endl;
    }
    cout << "+------------------------------+" << endl;
    cout << "您的群组 : " << endl;
    for (auto &group : currentUserGroupList)
    {
        cout << "您群组的ID : " << group.getId() << " 您群组的名字 : " << group.getName() <<" 群组描述 : " << group.getDesc()<< endl;
    }
    cout << "+------------------------------+" << endl;
}

// 接收线程
void readTaskHandler(int clientfd)
{
    while (1)
    {
        char buf[1024] = {0};
        int len = recv(clientfd, buf, 1024, 0);
        if (len == 0 || len == -1)
        {
            // 接收失败
            close(clientfd);
            exit(-1);
        }

        json js = json::parse(buf);
        if (js["msgid"].get<int>() == SINGLE_CHAT_MSG)
        {
            cout << js["name"] << " : " << js["msg"] << endl;
        }
        if(js["msgid"] == GROUP_CHAT_MSG){
            cout <<" 组ID为 " <<js["groupid"]<< " 的用户: " << js["msg"] << endl;
        }
    }
}

// commandHandlerMap中的相关回调
void help(int clientfd)
{
    for (auto &i : commandMap)
    {
        cout << i.first << " : " << i.second << endl;
    }
}

void chat(int clientfd)
{
    int to_id = -1;
    string msg;
    cout << "请输入对方ID" << endl;
    cin >> to_id;
    cin.get(); // 读取缓冲区残留的回车
    cout << "请输入聊天内容" << endl;
    cin >> msg;
    cin.get(); // 读取缓冲区残留的回车

    json js;
    js["msgid"] = SINGLE_CHAT_MSG;
    js["id"] = currentUser.getId();
    js["name"] = currentUser.getName();
    js["to_id"] = to_id;
    js["msg"] = msg;
    string request = js.dump();

    int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send msg error:" << request << endl;
    }
}

void addfriend(int clientfd)
{
    int friendid = -1;
    cout << "请输入对方ID" << endl;
    cin >> friendid;
    cin.get(); // 读取缓冲区残留的回车

    json js;
    js["msgid"] = ADD_FRIEND_MSG;
    js["id"] = currentUser.getId();
    js["friendid"] = friendid;
    string request = js.dump();

    int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send msg error:" << request << endl;
    }
    else
    {
        char buf[1024] = {0};
        len = recv(clientfd, buf, 1024, 0);
        if (len == -1)
        {
            cerr << "recv error" << endl;
        }
        else
        {
            json js = json::parse(buf);
            if (js["msgid"] == ADD_FRIEND_ACK && js["errno"].get<int>() == 1)
            {
                cout << js["errmsg"] << endl;
            }
            else
            {
                cout << "添加成功" << endl;
            }
        }
    }
}

void creategroup(int clientfd){
    string groupname = "";
    string groupdesc = "";
    cout << "请输入组名" << endl;
    cin >> groupname;
    cin.get(); // 读取缓冲区残留的回车
    cout << "请输入组描述" <<endl;
    cin >> groupdesc;
    cin.get();

    json js;
    js["msgid"] = CREATE_GROUP_MSG;
    js["id"] = currentUser.getId();
    js["groupname"] = groupname;
    js["groupdesc"] = groupdesc;
    string request = js.dump();

    int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send msg error:" << request << endl;
    }
}

void addgroup(int clientfd){
    int groupid = -1;
    cout << "请输入组ID" << endl;
    cin >> groupid;
    cin.get(); // 读取缓冲区残留的回车

    json js;
    js["msgid"] = ADD_GROUP_MSG;
    js["id"] = currentUser.getId();
    js["groupid"] = groupid;
    string request = js.dump();

    int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send msg error:" << request << endl;
    }
}

void groupchat(int clientfd){
    int groupid = -1;
    string str = "";
    cout << "请输入组ID" << endl;
    cin >> groupid;
    cin.get(); // 读取缓冲区残留的回车
    cout << "请输入聊天内容" << endl;
    cin >> str;
    cin.get(); // 读取缓冲区残留的回车

    json js;
    js["msgid"] = GROUP_CHAT_MSG;
    js["id"] = currentUser.getId();
    js["groupid"] = groupid;
    js["msg"] = str;
    string request = js.dump();

    int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send msg error:" << request << endl;
    }
}

void loginout(int clientfd){

}

// 注册的回调
unordered_map<string, function<void(int)>> commandHandlerMap = {
    {"help", help},
    {"chat", chat},
    {"addfriend", addfriend},
    {"creategroup", creategroup},
    {"addgroup", addgroup},
    {"groupchat", groupchat},
    {"loginout", loginout},
    {"show", showCurrentUserData}};

// 主聊天页面程序
void mainMenu(int clientfd)
{
    help(clientfd);
    char buf[1024] = {0};

    while (1)
    {
        cin.getline(buf, 1024);
        string commandBuf(buf);
        auto it = commandHandlerMap.find(commandBuf);
        if (it == commandHandlerMap.end())
        {
            cerr << "command error!" << endl;
            continue;
        }
        // 调用回调
        it->second(clientfd);
    }
}

// 聊天客户端的实现，main线程用作发送线程，子线程用作接收线程
int main(int argc, char **argv)
{

    if (argc < 3)
    {
        cerr << "command invalid! example:./ChatServer 127.0.0.1 6000" << endl;
        exit(-1);
    }

    // 通过命令解析传递的参数地址
    char *ip = argv[1];
    uint16_t port = atoi(argv[2]);

    // 创建client端的socket
    int clientfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == clientfd)
    {
        cerr << "socket create error" << endl;
        exit(-1);
    }

    // 填写client连接需要的server信息：ip+port
    sockaddr_in server;
    memset(&server, 0, sizeof(sockaddr_in));

    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = inet_addr(ip);

    // client和server进行连接
    if (-1 == connect(clientfd, (sockaddr *)&server, sizeof(sockaddr_in)))
    {
        cerr << "connect error" << endl;
        close(clientfd);
        exit(-1);
    }

    // 打印client菜单的死循环
    while (1)
    {
        cout << "+------------------------------+" << endl;
        cout << "|----------1.sign up-----------|" << endl;
        cout << "|----------2.login-------------|" << endl;
        cout << "|----------7.quit--------------|" << endl;
        cout << "+------------------------------+" << endl;

        // 接收输入
        int index = 0;
        cin >> index;
        cin.get(); // 读取缓冲区残留的回车

        // 判断
        switch (index)
        {
        case 1:
        {
            /* register */
            char name[50] = {0};
            char pwd[50] = {0};
            cout << "username:" << endl;
            cin.getline(name, 50);
            cout << "password" << endl;
            cin.getline(pwd, 50);

            // 组装json文件
            json js;
            js["msgid"] = REG_MSG;
            js["name"] = name;
            js["password"] = pwd;
            string request = js.dump();

            int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);
            if (len == -1)
            {
                cerr << "send reg msg error:" << request << endl;
            }
            else
            {
                char buf[1024] = {0};
                len = recv(clientfd, buf, 1024, 0);
                if (len == -1)
                {
                    cerr << "recv msg error" << endl;
                }
                else
                {
                    json res = json::parse(buf);
                    if (0 != res["errno"].get<int>())
                    {
                        cerr << "register failed!" << endl;
                    }
                    else
                    {
                        cout << name << "register success, userid is " << res["id"] << endl;
                    }
                }
            }
            break;
        }

        case 2:
        {
            /* login
                request:name && password */
            char name[50] = {0};
            char pwd[50] = {0};
            cout << "username:" << endl;
            cin.getline(name, 50);
            cout << "password" << endl;
            cin.getline(pwd, 50);

            // 组装json文件
            json js;
            js["msgid"] = LOGIN_MSG;
            js["name"] = name;
            js["password"] = pwd;
            string request = js.dump();

            int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);
            if (len == -1)
            {
                cerr << "send login msg error:" << request << endl;
            }
            else
            {
                char buf[1024] = {0};
                len = recv(clientfd, buf, 1024, 0);
                if (len == -1)
                {
                    cerr << "recv login error" << endl;
                }
                else
                {
                    json res = json::parse(buf);
                    if (0 != res["errno"].get<int>())
                    {
                        cerr << "login failed! " << res["errmsg"] << endl; // 打印服务器返回的错误原因
                    }
                    else
                    {
                        cout << name << "login success, userid is " << res["id"] << endl;
                        // 更新本地存储的User信息
                        currentUser.setId(res["id"].get<int>());
                        currentUser.setName(name);

                        // 记录当前的好友列表信息
                        if (res.contains("friends"))
                        {
                            vector<vector<string>> vecVec = res["friends"];
                            for (auto &vec : vecVec)
                            { // vec[0]:id, vec[1]:name, vec[2]:state
                                User user(vec[1], "", vec[2], stoi(vec[0]));
                                currentUserFriendList.emplace_back(user);
                            }
                        }

                        // 记录当前群组信息
                        if (res.contains("groups"))
                        {
                            vector<string> vec1 = res["groups"];
                            for (string &groupstr : vec1)
                            {
                                json grpjs = json::parse(groupstr);
                                Group group;
                                group.setId(grpjs["id"].get<int>());
                                group.setName(grpjs["groupname"]);
                                group.setDesc(grpjs["groupdesc"]);

                                vector<string> vec2 = grpjs["users"];
                                for (string &userstr : vec2)
                                {
                                    GroupUser user;
                                    json js = json::parse(userstr);
                                    user.setId(js["id"].get<int>());
                                    user.setName(js["name"]);
                                    user.setState(js["state"]);
                                    user.setRole(js["role"]);
                                    group.getUsers().emplace_back(user);
                                }
                                currentUserGroupList.emplace_back(group);
                            }
                        }

                        // 显示登录页面的信息
                        showCurrentUserData(1);

                        // 显示离线消息
                        if (res.contains("offlinemsg"))
                        {
                            cout << "您的离线消息 : " << endl;
                            
                            vector<string> vec = res["offlinemsg"]; 
                            for (string &str : vec)
                            {
                                json js = json::parse(str);
                               
                                cout << js["name"] << " : " << js["msg"] << endl;
                            }
                            cout << "+------------------------------+" << endl; 
                        }

                        // 登录成功，启动接收线程负责接收数据
                        thread readTask(readTaskHandler, clientfd);
                        readTask.detach();

                        // 进入聊天菜单页面
                        mainMenu(clientfd);
                    }
                }
            }
            break;
        }
        case 7:
        {
            /* quit */
            close(clientfd);
            exit(0);
            break;
        }
        default:
        {
            cerr << "invalid input!" << endl;
            break;
        }
        }
    }
    return 0;
}
